/*
 * Ina226App.cpp
 *
 *  Created on: 2021��7��25��
 *      Author: vicent-PC
 */

#include "Ina226App.h"

#include "../c3log.h"
#include <Trace.h>

#define LOG_TAG "Ina226App"

#define INA226_VAL_LSB 2.5f  //分流电压 LSB 2.5uV
#define Voltage_LSB 1.25f    //总线电压 LSB 1.25mV
#define CURRENT_LSB 10.0f    //电流LSB 10mA
#define POWER_LSB 25 * CURRENT_LSB
#define CAL 456  // 0.00512/(Current_LSB*R_SHUNT) = 470  //电流偏大改小

#define SHUNT_R_calibration (0.008)
#define SHUNT_R (0.020 + SHUNT_R_calibration)

Ina226App::Ina226App(I2cInterface intf) {
    // TODO Auto-generated constructor stub
    i2cIntf = intf;
}

Ina226App::~Ina226App() {
    // TODO Auto-generated destructor stub
}

void Ina226App::checkConfig() {
    const char * shutterMode = "unknown";
    switch (ina.getMode()) {
        case INA226_MODE_POWER_DOWN:
            shutterMode = ("Power-Down");
            break;
        case INA226_MODE_SHUNT_TRIG:
            shutterMode = ("Shunt Voltage, Triggered");
            break;
        case INA226_MODE_BUS_TRIG:
            shutterMode = ("Bus Voltage, Triggered");
            break;
        case INA226_MODE_SHUNT_BUS_TRIG:
            shutterMode = ("Shunt and Bus, Triggered");
            break;
        case INA226_MODE_ADC_OFF:
            shutterMode = ("ADC Off");
            break;
        case INA226_MODE_SHUNT_CONT:
           shutterMode = ("Shunt Voltage, Continuous");
            break;
        case INA226_MODE_BUS_CONT:
           shutterMode = ("Bus Voltage, Continuous");
            break;
        case INA226_MODE_SHUNT_BUS_CONT:
            shutterMode = ("Shunt and Bus, Continuous");
            break;
        default:
            shutterMode = ("unknown");
    }

    LOGI("[Info] Shutter mode: %s", shutterMode);

    const char * samplesMode = "unknown";
    switch (ina.getAverages()) {
        case INA226_AVERAGES_1:
            samplesMode = ("1 sample");
            break;
        case INA226_AVERAGES_4:
            samplesMode = ("4 samples");
            break;
        case INA226_AVERAGES_16:
            samplesMode = ("16 samples");
            break;
        case INA226_AVERAGES_64:
            samplesMode = ("64 samples");
            break;
        case INA226_AVERAGES_128:
            samplesMode = ("128 samples");
            break;
        case INA226_AVERAGES_256:
            samplesMode = ("256 samples");
            break;
        case INA226_AVERAGES_512:
            samplesMode = ("512 samples");
            break;
        case INA226_AVERAGES_1024:
            samplesMode = ("1024 samples");
            break;
        default:
            LOGI("unknown");
    }
    LOGI("[Info] Samples average mode: %s", samplesMode);

    const char * conversionTimeStr = "unknown";
    switch (ina.getBusConversionTime()) {
        case INA226_BUS_CONV_TIME_140US:
            conversionTimeStr = "140uS";
            break;
        case INA226_BUS_CONV_TIME_204US:
            conversionTimeStr = ("204uS");
            break;
        case INA226_BUS_CONV_TIME_332US:
            conversionTimeStr = ("332uS");
            break;
        case INA226_BUS_CONV_TIME_588US:
            conversionTimeStr = ("558uS");
            break;
        case INA226_BUS_CONV_TIME_1100US:
            conversionTimeStr = ("1.100ms");
            break;
        case INA226_BUS_CONV_TIME_2116US:
            conversionTimeStr = ("2.116ms");
            break;
        case INA226_BUS_CONV_TIME_4156US:
            conversionTimeStr = ("4.156ms");
            break;
        case INA226_BUS_CONV_TIME_8244US:
            conversionTimeStr = ("8.244ms");
            break;
        default:
            conversionTimeStr = ("unknown");
    }
    LOGI("[Info] Bus conversion time: %s", conversionTimeStr);

    const char * shuntConversionTime = "unknown";
    switch (ina.getShuntConversionTime()) {
        case INA226_SHUNT_CONV_TIME_140US:
            shuntConversionTime = ("140uS");
            break;
        case INA226_SHUNT_CONV_TIME_204US:
            shuntConversionTime = ("204uS");
            break;
        case INA226_SHUNT_CONV_TIME_332US:
            shuntConversionTime = ("332uS");
            break;
        case INA226_SHUNT_CONV_TIME_588US:
            shuntConversionTime = ("558uS");
            break;
        case INA226_SHUNT_CONV_TIME_1100US:
            shuntConversionTime = ("1.100ms");
            break;
        case INA226_SHUNT_CONV_TIME_2116US:
            shuntConversionTime = ("2.116ms");
            break;
        case INA226_SHUNT_CONV_TIME_4156US:
            shuntConversionTime = ("4.156ms");
            break;
        case INA226_SHUNT_CONV_TIME_8244US:
            shuntConversionTime = ("8.244ms");
            break;
        default:
            shuntConversionTime = ("unknown");
    }
    LOGI("[Info] Shunt conversion time: %s", shuntConversionTime);

    LOGI("[Info] Max possible current:%.3f A", ina.getMaxPossibleCurrent());
    LOGI("[Info] Max current:%.3f A", ina.getMaxCurrent());
    LOGI("[Info] Max shunt voltage:%.3f V", ina.getMaxShuntVoltage());
    LOGI("[Info] Max power:%.3f W", ina.getMaxPower());
}

int Ina226App::setup() {
    TRACE_B();
    int ret = 0;
    int retryCnt = 3;

    if (!i2cIntfInited) {
        // I2cInterface init, Default INA226 address is 0x40
        I2cInterface intfINA226(INA226_I2C_ADDR);
        i2cIntf = intfINA226;
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }

    for (int i = 0; i < retryCnt; i++) {
        ret = ina.beginProbe(i2cIntf);
        if (0 != ret) {
            LOGW("%s beginProbe fail: %d", __func__, i);
            vTaskDelay(500 / portTICK_PERIOD_MS);
        } else {
            LOGI("%s beginProbe suc", __func__);
            break;
        }
    }
    if (0 != ret) {
        LOGE("%s begin fail", __func__);
    }


    // Configure INA226
    // I2C spped limit (100Kbit/s, 400Kbit/s, 3.4Mbit/s),
    // INA226_BUS_CONV_TIME_140US
    ret = ina.configure();
    if (0 != ret) {
        LOGE("%s configure fail", __func__);
        return ret;
    } else {
        LOGI("%s configure suc", __func__);
    }

    // Calibrate INA226. My Rshunt = 0.02 ohm, Max excepted current = 4A
    ret = ina.calibrate(SHUNT_R, 4);  // key
    if (0 != ret) {
        LOGE("%s calibrate fail", __func__);
        return ret;
    } else {
        LOGI("%s calibrate suc", __func__);
    }

    // Display configuration
    checkConfig();

    LOGI("Initialize INA226 done X");
    return ret;
}

unsigned short CRC_CHECK(unsigned char *Buf, unsigned char CRC_CNT) {
    unsigned short CRC_Temp;
    int i, j;
    CRC_Temp = 0xffff;

    for (i = 0; i < CRC_CNT; i++) {
        CRC_Temp ^= Buf[i];
        for (j = 0; j < 8; j++) {
            if (CRC_Temp & 0x01)
                CRC_Temp = (CRC_Temp >> 1) ^ 0xA001;
            else
                CRC_Temp = CRC_Temp >> 1;
        }
    }
    return (CRC_Temp);
}

void VisualScope_Output(float data1, float data2, float data3, float data4) {
    int temp[4] = {0};
    unsigned int temp1[4] = {0};
    unsigned char databuf[10] = {0};
    int i = 0;
    unsigned short CRC16 = 0;

    temp1[0] = (unsigned int)data1;
    temp1[1] = (unsigned int)data2;
    temp1[2] = (unsigned int)data3;
    temp1[3] = (unsigned int)data4;

    for (i = 0; i < 4; i++) {
        databuf[i * 2] = (unsigned char)(temp1[i] % 256);
        databuf[i * 2 + 1] = (unsigned char)(temp1[i] / 256);
    }

    CRC16 = CRC_CHECK(databuf, 8);
    databuf[8] = CRC16 % 256;
    databuf[9] = CRC16 / 256;
    for (i = 0; i < 10; i++) {
        printf("%u", databuf[i]);
    }
}

/**
 * return previous voltage
 */
void Ina226App::pollIVP() {
    static int cnt = 0;
    mV = ina.readBusVoltage();
    static double vol_sum1000 = 0.0;
    static double power_sum1000 = 0.0;
    float shunt_vol = ina.readShuntVoltage();
    // float shunt_current = ina.readShuntCurrent();
    // float bus_power = ina.readBusPower();
    mI = shunt_vol / SHUNT_R;  // R
    mP = mI * mV;
    float bus_power = mV * mI;
    // printf("1,%.3f;2,%.3f;3,%.6lf;4,%.6f\n", mV, mP, shunt_vol, mI);
    if (cnt % 1000 == 0) {
        cnt = 0;
        mBus_vol_avg_ref = vol_sum1000 / 1000;
        mBus_vol_avg_power_ref = power_sum1000 / 1000;
        vol_sum1000 = 0;
        power_sum1000 = 0;
    }
    cnt++;
    vol_sum1000 += mV;
    power_sum1000 += bus_power;

    mBus_vol_avg_cur = vol_sum1000 / cnt;
}

void Ina226App::getIVP(float &cur, float &vol, float &power) {
    pollIVP();
    cur = mI;
    vol = mV;
    power = mP;
    // printf("mI, mV, mP: %.3f %.3f %.3f\n", mI, mV, mP);
}

void Ina226App::getVol_Power(float &cur, float &ref, float &power_ref) {
    cur = mI;
    ref = mBus_vol_avg_ref;
    power_ref = mBus_vol_avg_power_ref;
}

void Ina226App::main() {
    setup();
    vTaskDelay(5 / portTICK_PERIOD_MS);
    for (int i = 0; i < 1000 * 1000 * 1000; i++) {
        // LOGI("Bus U:%.3fV  P:%.3fW    Shunt U:%.6lfV  I:%.6f A",
        // ina.readBusVoltage(), ina.readBusPower(), ina.readShuntVoltage(),
        // ina.readShuntCurrent()); vTaskDelay(1000 / portTICK_PERIOD_MS);
        float bus_vol = ina.readBusVoltage();
        float shunt_vol = ina.readShuntVoltage();
        float shunt_current = ina.readShuntCurrent();
        float bus_power = ina.readBusPower();
        printf("1,%.3f;2,%.3f;3,%.6lf;4,%.6f\n", bus_vol, bus_power, shunt_vol,
               shunt_current);
        // printf("C1,%.3f;C2,%.3f\n", ina.readBusVoltage(),
        // ina.readBusPower()); VisualScope_Output(ina.readBusVoltage(),
        // ina.readBusPower(), ina.readShuntVoltage(), ina.readShuntCurrent());
    }
}
